import { GlobalOutlined, TeamOutlined } from '@ant-design/icons';
import { Button, Form, Input, Layout, Modal, Select, Space, Tree } from "antd";
import { useCallback, useEffect, useReducer } from 'react';
import alert from '../../utils/alert';
import client from '../../utils/client';
import tree from '../../utils/tree';
import styles from '../common.module.css';
import org_styles from './organization.module.css';

const TYPE_DEPT = 1;

export default function Organization(props) {
  const [state, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'loading':
        return {
          ...state,
          loading: true,
          exporting: false,
          selected: null,
          editing: null,
        };
      case 'loaded':
        return {
          ...state,
          loading: false,
          tree_key: Date.now(),
          tree: action.tree,
          defaultExpandedKeys: action.tree.map(d => d.key),
        };
      case 'select':
        return { ...state, selected: state.editing ? state.selected : action.selected };
      case 'add':
        return { ...state, editing: { 上级: state.selected ? state.selected.key : null } };
      case 'edit':
        return { ...state, editing: state.selected.data };
      case 'save':
        return { ...state, tree: action.tree, editing: null };
      case 'cancel':
        return { ...state, editing: null };
      case 'exporting':
        return { ...state, exporting: true };
      case 'exported':
        return { ...state, exporting: false };
      default:
        return state;
    }
  }, {
    tree_key: Date.now(),
    loading: true,
    tree: [],
    defaultExpandedKeys: [],
    exporting: false,
    // 选中的树节点
    selected: null,
    // 编辑中的记录行
    editing: null,
  });
  const [form] = Form.useForm();

  // Mount之后自动加载数据
  useEffect(() => {
    reload();
    // eslint-disable-next-line
  }, []);

  // 选中项变化或者编辑状态变化后, 都要更新表单的值
  useEffect(() => {
    if (state.editing) {
      form.resetFields();
      form.setFieldsValue(state.editing);
    } else if (state.selected) {
      form.setFieldsValue(state.selected.data);
    } else {
      form.resetFields();
    }
  }, [state.selected, state.editing, form]);

  const reload = useCallback(() => {
    dispatch({ type: 'loading' });
    client.job('TreeR', {
      Card: 'B.组织机构',
      Model: ['名称', '编码', '标准名称', '标准编码', '机构类型', '归属公司', 'ID路径', '名称路径', '层级', '序号', '上级'],
      Filter: [{ or: [['上级', 'is', null], ['上级', '=', '']] }],
      Order: { '序号': 'asc' },
      Parent: '上级',
    }).then(({ Rows }) => {
      dispatch({
        type: 'loaded',
        tree: tree.map(Rows, item => ({
          key: item.ID,
          title: item.编码 ? `${item.名称} (${item.编码})` : item.名称,
          icon: item.机构类型 === TYPE_DEPT ? <TeamOutlined /> : <GlobalOutlined />,
          data: item,
        })),
      });
    });
  }, []);

  const save = useCallback(() => {
    let ID;
    let parent = !state.editing.上级 ? null : tree.find(state.tree, node => node.key === state.editing.上级);
    const promise = state.editing.ID ? Promise.resolve() : client.job('GetGUID').then(ids => ID = ids[0]);

    form.validateFields().then(values => {
      promise.then(() => {
        // 更新到记录
        const record = Object.assign({ ID }, state.editing, values);
        Object.assign(record, {
          ID路径: (parent ? parent.data.ID路径 : '') + '/' + record.ID,
          名称路径: (parent ? parent.data.名称路径 : '') + '/' + record.名称,
          层级: parent ? parent.data.层级 + 1 : 1,
          上级: parent ? parent.data.ID : null,
          归属公司: parent ? (parent.data.机构类型 === TYPE_DEPT ? parent.data.归属公司 : parent.data.ID) : null,
          序号: record.序号 || Date.now(),
        });

        // 更新到节点
        if (state.editing.ID) {
          // 修改节点可以直接更新
          Object.assign(state.selected.data, record);
          state.selected.title = record.名称;
          // 更新所有后代子节点
          if (state.selected.children && state.selected.children.length > 0) {
            tree.each(state.selected.children, (n, i, a, p = state.selected) => {
              n.data.名称路径 = p.data.名称路径 + '/' + n.data.名称;
              n.data.归属公司 = p.data.机构类型 === TYPE_DEPT ? p.data.归属公司 : p.data.ID;
            });
          }
        } else {
          // 新增节点要追加到上级节点中
          const node = {
            key: record.ID,
            title: record.名称,
            icon: record.机构类型 === TYPE_DEPT ? <TeamOutlined /> : <GlobalOutlined />,
            data: record,
          };
          if (parent) {
            parent.children = parent.children || [];
            parent.children.push(node);
          } else {
            state.tree.push(node);
          }
        }

        client.job('CardW', {
          Card: 'B.组织机构',
          Model: ['名称', '编码', '标准名称', '标准编码', '机构类型', '归属公司', 'ID路径', '名称路径', '层级', '序号', '上级'],
          Record: record,
        }).then(() => {
          if (state.editing.ID && state.selected && state.selected.children && state.selected.children.length > 0) {
            const t = tree.map(state.selected.children, n => n.data);
            client.job('CardW', {
              Card: 'B.组织机构',
              Model: ['归属公司', '名称路径'],
              Records: tree.list(t),
            }).then(() => dispatch({ type: 'save', tree: [...state.tree] }));
          } else {
            dispatch({ type: 'save', tree: [...state.tree] });
          }
        });
      });
    }).catch(() => null);
  }, [form, state.tree, state.selected, state.editing]);

  const remove = useCallback(() => {
    if (!state.selected) {
      alert('无效操作', '请先选中您要删除的记录');
      return;
    }

    Modal.confirm({
      title: '删除确认',
      content: "数据删除后不可恢复, 请确定",
      onOk() {
        client.job('TreeD', {
          Card: 'B.组织机构',
          Parent: '上级',
          Record: state.selected.data,
        }).then(() => {
          const data = tree.remove(state.tree, node => node === state.selected);
          dispatch({ type: 'loaded', tree: data });
          dispatch({ type: 'select' });
        });
      }
    });
  }, [state.selected, state.tree]);

  const move = useCallback(({ dragNode, node, dropToGap }) => {
    let drag, dropParent, dropIndex;
    // 先移除drag节点, 同时拿到对应记录
    tree.remove(state.tree, n => {
      if (n.key === dragNode.key) {
        drag = n;
        return true;
      }
    });
    // 找到drop节点的位置信息
    tree.each(state.tree, (n, index, arr, parent) => {
      if (n.key === node.key) {
        dropParent = parent;
        dropIndex = index;
      }
    });
    if (dropToGap) {
      // 移动到drop节点的后面
      (dropParent ? dropParent.children : state.tree).splice(dropIndex + 1, 0, drag);
      // 更新对应记录
      Object.assign(dragNode.data, {
        ID路径: (dropParent ? dropParent.data.ID路径 : '') + '/' + dragNode.data.ID,
        名称路径: (dropParent ? dropParent.data.名称路径 : '') + '/' + dragNode.data.名称,
        层级: node.data.层级,
        上级: node.data.上级,
        归属公司: node.data.归属公司,
        序号: node.data.序号 * 2,
      });
    } else {
      // 移动到drop节点的子节点中
      node.children = node.children || [];
      node.children.unshift(drag);
      // 更新对应记录
      Object.assign(dragNode.data, {
        ID路径: node.data.ID路径 + '/' + dragNode.data.ID,
        名称路径: node.data.名称路径 + '/' + dragNode.data.名称,
        层级: node.data.层级 + 1,
        上级: node.data.ID,
        归属公司: node.data.机构类型 === TYPE_DEPT ? node.data.归属公司 : node.data.ID,
        序号: node.children[1] ? node.children[1].data.序号 / 2 : Date.now(),
      });
    }
    client.job('CardW', {
      Card: 'B.组织机构',
      Model: ['名称', '编码', '标准名称', '标准编码', '机构类型', '归属公司', 'ID路径', '名称路径', '层级', '序号', '上级'],
      Record: dragNode.data,
    }).then(() => {
      if (dragNode.children && dragNode.children.length > 0) {
        // 递归遍历所有子节点, 更新其名称路径和归属公司
        tree.each(dragNode.children, (n, i, a, p = dragNode) => {
          n.data.ID路径 = p.data.ID路径 + '/' + n.data.ID;
          n.data.名称路径 = p.data.名称路径 + '/' + n.data.名称;
          n.data.归属公司 = p.data.机构类型 === TYPE_DEPT ? p.data.归属公司 : p.data.ID;
          n.data.层级 = p.data.层级 + 1;
        });
        const t = tree.map(dragNode.children, n => n.data);
        client.job('CardW', {
          Card: 'B.组织机构',
          Model: ['归属公司', 'ID路径', '名称路径', '层级'],
          Records: tree.list(t),
        }).then(() => dispatch({ type: 'save', tree: [...state.tree] }));
      }
    });
    dispatch({ type: 'save', tree: [...state.tree] });
  }, [state.tree]);

  const export_xls = useCallback(() => {
    dispatch({ type: 'exporting' });
    client.export_xls('B.TreeRExport', {
      Card: 'B.组织机构',
      Model: ['名称', '编码', '标准名称', '标准编码', '机构类型', '归属公司', 'ID路径', '名称路径', '层级', '序号', '上级'],
      Filter: [{ or: [['上级', 'is', null], ['上级', '=', '']] }],
      Order: { '序号': 'asc' },
      Parent: '上级',
    }).then(() => dispatch({ type: 'exported' }));
  }, []);

  function import_xls() {
    client.import('B.CardWImport', {
      Card: 'B.组织机构',
      Model: ['名称', '编码', '标准名称', '标准编码', '机构类型', '归属公司', 'ID路径', '名称路径', '层级', '序号', '上级'],
    }).then(reload);
  }

  return (
    <Layout style={{ minWidth: 600 }}>
      <Layout.Header className={styles.toolbar}>
        <Space size={[8, 8]} wrap>
          <Button onClick={reload}>刷新</Button>
          <Button type="primary" onClick={() => dispatch({ type: 'add' })} disabled={state.editing}>{state.selected ? '新增子机构' : '新增根机构'}</Button>
          <Button onClick={() => dispatch({ type: 'edit' })} disabled={state.editing || !state.selected}>修改</Button>
          <Button type="primary" onClick={save} disabled={!state.editing}>保存</Button>
          <Button onClick={() => dispatch({ type: 'cancel' })} disabled={!state.editing}>取消</Button>
          <Button onClick={remove} disabled={state.editing || !state.selected}>删除</Button>
          <Button loading={state.exporting} onClick={import_xls}>导入</Button>
          <Button loading={state.exporting} onClick={export_xls}>导出</Button>
        </Space>
      </Layout.Header>
      <Layout>
        <Layout.Sider width={500}>
          <Tree key={state.tree_key} draggable={{ icon: false }} blockNode showIcon rootClassName={org_styles.tree}
            treeData={state.tree} defaultExpandedKeys={state.defaultExpandedKeys}
            selectedKeys={!state.selected ? [] : [state.selected.key]}
            onSelect={(_, { selectedNodes }) => dispatch({ type: 'select', selected: selectedNodes[0] })}
            onDrop={(info) => move(info)}
          />
        </Layout.Sider>
        <Layout.Content style={{ padding: 15 }}>
          <Form form={form} labelCol={{ span: 4 }} disabled={!state.editing}>
            <Form.Item label="编码" name="编码" rules={[{ required: true }]}>
              <Input allowClear={true} autoComplete="off" />
            </Form.Item>
            <Form.Item label="名称" name="名称" rules={[{ required: true }]}>
              <Input allowClear={true} autoComplete="off" />
            </Form.Item>
            <Form.Item label="标准编码" name="标准编码">
              <Input allowClear={true} autoComplete="off" />
            </Form.Item>
            <Form.Item label="标准名称" name="标准名称">
              <Input allowClear={true} autoComplete="off" />
            </Form.Item>
            <Form.Item label="机构类型" name="机构类型" rules={[{ required: true }]}>
              <Select allowClear={true}>
                <Select.Option value={0}>公司</Select.Option>
                <Select.Option value={1}>部门</Select.Option>
                <Select.Option value={2}>分支机构</Select.Option>
                <Select.Option value={3}>虚拟组织</Select.Option>
              </Select>
            </Form.Item>
            <Form.Item label="名称路径" name="名称路径">
              <Input disabled />
            </Form.Item>
          </Form>
        </Layout.Content>
      </Layout>
    </Layout>
  )
}